package com.treasure.mall.zbqmallapi.controller;

import com.treasure.mall.biz.bo.config.BasicsConfig;
import com.treasure.mall.biz.bo.oss.OssConfig;
import com.treasure.mall.biz.dto.condition.AdvanceLogSearchCondition;
import com.treasure.mall.biz.dto.condition.AuctionBidCondition;
import com.treasure.mall.biz.dto.condition.UserSearchCondition;
import com.treasure.mall.biz.dto.order.UserOrderCountDTO;
import com.treasure.mall.biz.dto.pay.PaymentBillSaveDTO;
import com.treasure.mall.biz.dto.user.AppLoginAsMobileDTO;
import com.treasure.mall.biz.dto.user.AppLoginDTO;
import com.treasure.mall.biz.dto.user.LoginDTO;
import com.treasure.mall.biz.dto.user.ModifyUserDTO;
import com.treasure.mall.biz.dto.wechat.CreateWxaCodeDTO;
import com.treasure.mall.biz.entity.auction.AuctionBidPO;
import com.treasure.mall.biz.entity.log.AdvanceLogPO;
import com.treasure.mall.biz.entity.pay.PaymentBillPO;
import com.treasure.mall.biz.entity.user.UserFollowPO;
import com.treasure.mall.biz.entity.user.UserPO;
import com.treasure.mall.biz.mapstruct.UserMapStruct;
import com.treasure.mall.biz.remote.live.TencentIMService;
import com.treasure.mall.biz.remote.quickpay.WechatPayService;
import com.treasure.mall.biz.remote.quickpay.dto.WxTradeOrderDTO;
import com.treasure.mall.biz.service.core.BaseConfigService;
import com.treasure.mall.biz.service.core.auction.AuctionBidService;
import com.treasure.mall.biz.service.core.blacklist.BlacklistService;
import com.treasure.mall.biz.service.core.community.CommunityArticleService;
import com.treasure.mall.biz.service.core.log.AdvanceLogService;
import com.treasure.mall.biz.service.core.pay.PayService;
import com.treasure.mall.biz.service.core.sms.SMSService;
import com.treasure.mall.biz.service.core.statistics.OrderStatisticsService;
import com.treasure.mall.biz.service.core.user.UserFollowService;
import com.treasure.mall.biz.service.core.user.UserService;
import com.treasure.mall.biz.service.core.user.WeChatService;
import com.treasure.mall.biz.vo.PageDataVO;
import com.treasure.mall.biz.vo.user.UserVO;
import com.treasure.mall.zbq.common.RandomUtils;
import com.treasure.mall.zbq.common.annotation.CurrentUser;
import com.treasure.mall.zbq.common.base.ApiResult;
import com.treasure.mall.zbq.common.base.ResultCodeEnum;
import com.treasure.mall.zbq.common.ienum.SystemEnums;
import com.treasure.mall.zbq.common.ienum.base.CodeDescEnumHelper;
import com.treasure.mall.zbq.common.ienum.log.LogDataType;
import com.treasure.mall.zbq.common.ienum.order.OrderEnums;
import com.treasure.mall.zbq.common.ienum.user.UserEnums;
import com.treasure.mall.zbq.common.oss.ResourceService;
import com.treasure.mall.zbqmallapi.annotation.AccessControl;
import com.treasure.mall.zbqmallapi.vo.auction.AuctionBidVO;
import com.treasure.mall.zbqmallapi.vo.user.UserBaseVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.*;

/**
 *
 * +---------------------------------------------------------
 * * @package: com.treasure.mall.zbqmallmanager.controller.front
 * * @author: guomw (guomwchen@foxmail.com)
 * * @date: 2020/6/11 14:35
 * * @since: V1.0.0
 * +---------------------------------------------------------
 * 注意：本内容仅限于内部传阅，禁止外泄以及用于其他的商业目的
 * Copyright 2019-2022 com.treasure.mall.zbqmallmanager.controller.front Inc. All rights reserved.
 */
@Slf4j
@RestController
@AccessControl(needLogin = true)
@Api(tags = "用户模块")
public class UserController {

    private static final String IMG_SUFFIX_PATH = "image/";

    @Autowired
    private UserService userService;
    @Autowired
    private ResourceService resourceService;
    @Autowired
    private TencentIMService imService;
    @Autowired
    private AdvanceLogService advanceLogService;
    @Autowired
    private PayService payService;
    @Autowired
    private BaseConfigService baseConfigService;
    @Autowired
    private WeChatService weChatService;
    @Autowired
    private WechatPayService wechatPayService;
    @Autowired
    private OrderStatisticsService orderStatisticsService;
    @Autowired
    private OssConfig ossConfig;
    @Autowired
    private SMSService smsService;
    @Autowired
    private AuctionBidService auctionBidService;
    @Autowired
    private UserFollowService userFollowService;
    @Autowired
    private CommunityArticleService articleService;
    @Autowired
    private UserFollowService followService;
    @Autowired
    private BlacklistService blacklistService;

    /**
     * @param user
     * @param userKey 如果用户没有登录，则使用该值生成用户Id签名
     * @return
     */
    @GetMapping("/im")
    @AccessControl
    public ApiResult im(@CurrentUser UserPO user, String userKey) {
        return ApiResult.ok(imService.clientLoginInformation(user, userKey));
    }


    /**
     * 根据code获取用户信息
     *
     * @param code
     * @return
     * @throws WxErrorException
     */
    @ApiOperation("微信code授权")
    @PostMapping("/loginByWechatCode")
    @AccessControl
    public ApiResult<UserVO> loginByWechatCode(String code) {
        return ApiResult.ok(userService.loginByWechatCode(code));
    }

    /**
     * 微信登录
     *
     * @param dto
     * @return
     * @throws WxErrorException
     */
    @ApiOperation("微信登录")
    @PostMapping("/loginAsWechatApp")
    @AccessControl
    public ApiResult<UserVO> loginAsWechatApp(@RequestBody LoginDTO dto) throws WxErrorException {
        return ApiResult.ok(userService.loginAsWechatApp(dto));
    }

    @ApiOperation("绑定手机登录")
    @PostMapping("/loginAsAppBindMobile")
    @AccessControl
    public ApiResult<UserVO> loginAsAppBindMobile(AppLoginAsMobileDTO dto) {

        if (smsService.checkVerifyCode(dto.getMobile(), dto.getVerifyCode())) {
            smsService.modifyVerifyUseStatus(dto.getMobile());
            return ApiResult.ok(userService.loginAsAppBindMobile(dto));
        }
        return ApiResult.error(ResultCodeEnum.SMS_VERIFY_FAILED);
    }

    /**
     * APP用户绑定微信
     *
     * @param userPO
     * @param dto
     * @return
     */
    @PostMapping("/loginAsAppBindWechat")
    @AccessControl(needLogin = true)
    public ApiResult loginAsAppBindWechat(@CurrentUser UserPO userPO, AppLoginDTO dto) {
        dto.setMobile(userPO.getMobile());
        if (StringUtils.isNotBlank(dto.getUnionId()) && userService.appAuthWechat(dto) != null) {
            return ApiResult.ok();
        }
        return ApiResult.error(ResultCodeEnum.PARAMETER_FAILED, "绑定微信失败");
    }


    @ApiOperation("App微信登录")
    @PostMapping("/loginAsApp")
    @AccessControl
    public ApiResult<UserVO> loginAsApp(AppLoginDTO dto) {
        return ApiResult.ok(userService.loginAsApp(dto));
    }


    /**
     * 获取用户信息
     *
     * @param fromUserId 邀请ID
     * @return
     */
    @ApiOperation("获取用户信息")
    @GetMapping("/who")
    public ApiResult who(@CurrentUser UserPO user, @RequestParam(required = false) Long fromUserId) {
        return ApiResult.ok(userService.who(user.getUserId(), fromUserId));
    }

    /**
     * 获取用户信息
     *
     * @param userId 用户ID
     * @return
     */
    @ApiOperation("获取用户信息")
    @GetMapping("/userInfo")
    @AccessControl
    public ApiResult getUserInfo(@RequestParam Long userId) {
        return ApiResult.ok(userService.who(userId, 0L));
    }

    /**
     * 修改昵称
     *
     * @param user
     * @param name
     */
    @ApiOperation("修改昵称")
    @PostMapping("/who/name")
    public ApiResult whoName(@CurrentUser UserPO user, @RequestParam String name) {
        if (StringUtils.isNotBlank(name)) {
            ModifyUserDTO dto = new ModifyUserDTO();
            dto.setUserId(user.getUserId());
            dto.setNickName(name);
            userService.modifyUserInfo(dto);
            return ApiResult.ok();
        }
        return ApiResult.error("昵称不能为空");
    }

    /**
     * @param user
     * @param file
     * @return
     * @throws IOException
     * @throws URISyntaxException
     */
    @ApiOperation("修改头像")
    @PostMapping("/who/avatar")
    public ApiResult whoAvatar(@CurrentUser UserPO user, @RequestParam(value = "avatar", required = false) MultipartFile file) throws IOException, URISyntaxException {
        //上传文件
        if (file != null) {
            String fileName = file.getOriginalFilename();
            assert fileName != null;
            String prefix = fileName.substring(fileName.lastIndexOf("."));
            String savePath = IMG_SUFFIX_PATH + UUID.randomUUID().toString().replaceAll("-", "")
                    + prefix;
            org.springframework.core.io.Resource resource = resourceService.upload(savePath, file.getInputStream());
            ModifyUserDTO dto = new ModifyUserDTO();
            dto.setUserId(user.getUserId());
            dto.setAvatar(resource.getURI().toString());
            userService.modifyUserInfo(dto);
            return ApiResult.ok();
        }
        return ApiResult.error("请上传文件...");
    }


    /**
     * 我的钱包接口
     *
     * @return
     */
    @ApiOperation("我的钱包接口")
    @GetMapping("/wallet")
    public ApiResult wallet(@CurrentUser UserPO user) {
        return ApiResult.ok(userService.myBalance(user.getUserId()));
    }

    /**
     * 获取团队概况
     *
     * @param user
     * @return
     */
    @ApiOperation("获取团队概况")
    @GetMapping("/inviteSummary")
    public ApiResult inviteSummary(@CurrentUser UserPO user) {
        return ApiResult.ok(userService.inviteSummary(user.getUserId()));
    }

    /**
     * 获取我的团队数据
     *
     * @param user
     * @param page
     * @param size
     * @param type merchant or buyer or normal
     * @return
     */
    @ApiOperation("获取我的团队数据")
    @GetMapping("/invitees")
    public ApiResult invitees(@CurrentUser UserPO user,
                              @RequestParam(required = false, defaultValue = "1") Integer page,
                              @RequestParam(required = false, defaultValue = "20") Integer size,
                              @RequestParam(required = false, defaultValue = "1") String type
    ) {
        UserSearchCondition condition = new UserSearchCondition();
//        condition.setParentId(user.getUserId());
        condition.setTreePath(user.getTreePath());
        condition.setUserId(user.getUserId());
        switch (type) {
            case "merchant":
                condition.setUserType(UserEnums.UserType.MEMBER);
                break;
            case "buyer":
                condition.setUserLevel(UserEnums.UserLevel.SINGLE_FAN);
                break;
            case "normal":
                condition.setUserLevel(UserEnums.UserLevel.GENERAL);
                break;
        }
        Page<UserPO> pageData = userService.findAll(page, size, condition);
        PageDataVO<UserVO> pageDataVO = new PageDataVO<>();
        pageDataVO.setPageSize(size);
        pageDataVO.setPageIndex(page);
        pageDataVO.setPageCount(pageData.getTotalPages());
        pageDataVO.setTotal(pageData.getTotalElements());
        pageDataVO.setRows(UserMapStruct.INSTANCE.pos2vos(pageData.getContent()));
        return ApiResult.ok(pageDataVO);
    }


    /**
     * @param balanceType 0 用户流水 1 商家货款流水 2 用户待入账  3商家待入账
     * @param is          1 则取收入，-1则取支出
     * @return
     */
    @ApiOperation("余额日志流水")
    @GetMapping("/moneyFlows/search/pageSearch")
    public ApiResult moneyFlows(@CurrentUser UserPO user,
                                @RequestParam(required = false, defaultValue = "1") int balanceType,
                                @RequestParam(required = false, defaultValue = "1") Integer is,
                                @RequestParam(required = false, defaultValue = "0") Integer page,
                                @RequestParam(required = false, defaultValue = "20") Integer size
    ) {
        AdvanceLogSearchCondition condition = new AdvanceLogSearchCondition();
        condition.setUserId(user.getUserId());
        LogDataType dataType = CodeDescEnumHelper.getEnumTypeByCode(LogDataType.class, balanceType);
        if (dataType != null) {
            condition.setDataType(dataType);
        } else {
            return ApiResult.error("无效参数值");
        }
        if (dataType.getCode().equals(LogDataType.MERCHANT_WAIT_BALANCE.getCode()) || dataType.getCode().equals(LogDataType.MERCHANT_BALANCE.getCode())) {
            condition.setUserId(user.getMerchantId());
        }


        condition.setIncome(is == 1);
        Page<AdvanceLogPO> pageData = advanceLogService.findAll(page, size, condition);
        PageDataVO<AdvanceLogPO> pageDataVO = new PageDataVO<>();
        pageDataVO.setPageSize(size);
        pageDataVO.setPageIndex(page);
        pageDataVO.setPageCount(pageData.getTotalPages());
        pageDataVO.setTotal(pageData.getTotalElements());
        pageDataVO.setRows(pageData.getContent());
        return ApiResult.ok(pageDataVO);
    }


    /**
     * 升级
     *
     * @param user
     * @param source  来源0 小程序  1 APP
     * @param request
     * @return
     */
    @ApiOperation("升级")
    @PostMapping("/upgrade")
    public ApiResult upgrade(@CurrentUser UserPO user, @RequestParam(required = false, defaultValue = "0") Integer source, HttpServletRequest request) {

        if (user.getMerchantPay()) {
            return ApiResult.error("您已经开过店了");
        }

        BasicsConfig basicsConfig = baseConfigService.getConfig().getBasicsConfig();
        PaymentBillSaveDTO dto = new PaymentBillSaveDTO();
        dto.setUserId(user.getUserId());
        dto.setDealType(OrderEnums.DealType.UPGRADE);
        dto.setAmount(basicsConfig.getUpgradeAmount());
        dto.setPayType(OrderEnums.PayType.WECHAT_PAY);
        dto.setOpenId(user.getWechatUser().getOpenId());
        dto.setOrderId(RandomUtils.randomFlowNo());
        dto.setThirdPay(true);
        PaymentBillPO po = payService.createBill(dto);

        WxTradeOrderDTO tradeOrderDTO = payService.pay(po);
        if (source == 1) {
            tradeOrderDTO.setTradeType(OrderEnums.TradeType.APP);
        }
        return ApiResult.ok(wechatPayService.JsApiBizPackage(tradeOrderDTO, request));
    }

    @ApiOperation("生成小程序码")
    @PostMapping("/wechat/min/unlimitedQRCode")
    public ApiResult wechatUnlimitedQRCode(CreateWxaCodeDTO dto) {
        try {
            File file = weChatService.createWxaCodeUnlimit(dto);
            String fileName = file.getName();
//            String prefix = fileName.substring(fileName.lastIndexOf("."));
            String savePath = IMG_SUFFIX_PATH + UUID.randomUUID().toString().replaceAll("-", "")
                    + ".png";
            Resource resource = resourceService.upload(savePath, new FileInputStream(file));
            return ApiResult.ok(resource.getURI().toString());
        } catch (Exception ex) {
            //如果创建小程序码失败，给一个默认二维码，避免用户无法分享
            log.error("unlimitedQRCode createWxaCodeUnlimit error", ex);
            return ApiResult.ok(MessageFormat.format("{0}qrcode/zbq_min_qrcode.jpg", ossConfig.getDomain()));
        }

    }

    @ApiOperation("用户订单统计")
    @GetMapping("/user/order/statistics")
    public ApiResult orderStatistics(@CurrentUser UserPO userPO) {
        UserOrderCountDTO orderCountDTO = orderStatisticsService.userOrderCount(userPO.getUserId());

        return ApiResult.ok(orderCountDTO);
    }


    @ApiOperation("保存用户分享图片")
    @PostMapping("/who/inviteQrcode")
    public ApiResult updateInviteQrcode(@CurrentUser UserPO user, @RequestParam(value = "inviteQrcode", required = false) MultipartFile file) throws IOException, URISyntaxException {
        //上传文件
        if (file != null) {
            String fileName = file.getOriginalFilename();
            assert fileName != null;
            String prefix = fileName.substring(fileName.lastIndexOf("."));
            String savePath = IMG_SUFFIX_PATH + UUID.randomUUID().toString().replaceAll("-", "")
                    + prefix;
            org.springframework.core.io.Resource resource = resourceService.upload(savePath, file.getInputStream());
            ModifyUserDTO dto = new ModifyUserDTO();
            dto.setUserId(user.getUserId());
            dto.setInviteQrcode(resource.getURI().toString());
            userService.modifyUserInfo(dto);
            return ApiResult.ok();
        }
        return ApiResult.error("请上传文件...");
    }

    @GetMapping("/auctionRecords")
    public ApiResult auctionRecords(
            @CurrentUser UserPO userPO,
            AuctionBidCondition condition,
            @RequestParam(required = false, defaultValue = "1") int page,
            @RequestParam(required = false, defaultValue = "10") int size
    ) {
        condition.setUserId(userPO.getUserId());
        Page<AuctionBidPO> pos = auctionBidService.findAll(page, size, condition);
        PageDataVO<AuctionBidVO> pageDataVO = new PageDataVO<>();
        pageDataVO.setPageCount(pos.getTotalPages());
        pageDataVO.setPageIndex(page);
        pageDataVO.setTotal(pos.getTotalElements());
        pageDataVO.setPageSize(size);
        List<AuctionBidVO> bidVOS = new ArrayList<>();
        pos.getContent().forEach(p -> bidVOS.add(new AuctionBidVO(p)));
        pageDataVO.setRows(bidVOS);

        return ApiResult.ok(pageDataVO);
    }

    /**
     * 关注
     *
     * @param userPO
     * @param follow 关注对象
     * @return 是否关注
     */
    @PostMapping("/follow/user")
    @AccessControl(needLogin = true)
    public ApiResult followByUserId(
            @CurrentUser UserPO userPO,
            Long follow
    ) {
        return ApiResult.ok(userFollowService.followToggle(userPO, follow));
    }

    /**
     * 我的粉丝
     *
     * @param userId
     * @return
     */
    @GetMapping("/followers")
    public ApiResult followers(
            Long userId,
            @RequestParam(required = false, defaultValue = "1") int page,
            @RequestParam(required = false, defaultValue = "20") int size
    ) {
        Page<UserFollowPO> pages = userFollowService.followers(userId, page, size);

        PageDataVO<UserBaseVO> pageDataVO = new PageDataVO<>();
        pageDataVO.setPageCount(pages.getTotalPages());
        pageDataVO.setPageIndex(page);
        pageDataVO.setPageSize(size);
        pageDataVO.setTotal(pages.getTotalElements());

        List<UserBaseVO> vos = new ArrayList<>();
        pages.getContent().forEach(p -> vos.add(new UserBaseVO(p.getUserPO())));
        pageDataVO.setRows(vos);

        return ApiResult.ok(pageDataVO);
    }

    /**
     * 我的关注
     *
     * @param userId
     * @return
     */
    @GetMapping("/follow")
    public ApiResult follow(
            Long userId,
            @RequestParam(required = false, defaultValue = "1") int page,
            @RequestParam(required = false, defaultValue = "20") int size
    ) {
        Page<UserFollowPO> pages = userFollowService.follow(userId, page, size);

        PageDataVO<UserBaseVO> pageDataVO = new PageDataVO<>();
        pageDataVO.setPageCount(pages.getTotalPages());
        pageDataVO.setPageIndex(page);
        pageDataVO.setPageSize(size);
        pageDataVO.setTotal(pages.getTotalElements());

        List<UserBaseVO> vos = new ArrayList<>();
        pages.getContent().forEach(p -> vos.add(new UserBaseVO(p.getUserPO())));
        pageDataVO.setRows(vos);

        return ApiResult.ok(pageDataVO);
    }

    /**
     * 我的关注数量
     *
     * @return
     */
    @GetMapping("/followCount")
    @AccessControl(needLogin = true)
    public ApiResult followCount(@CurrentUser UserPO userPO) {
        return ApiResult.ok(userFollowService.followCount(userPO.getUserId()));
    }

    /**
     * 获赞数量
     *
     * @param userPO
     * @return
     */
    @GetMapping("/likeCount")
    @AccessControl(needLogin = true)
    public ApiResult likeCount(@CurrentUser UserPO userPO) {
        return ApiResult.ok(articleService.likeCount(userPO.getUserId()));
    }

    /**
     * 作品数量
     *
     * @param userPO
     * @return
     */
    @GetMapping("/contentCount")
    public ApiResult contentCount(@CurrentUser UserPO userPO) {
        return ApiResult.ok(articleService.countByUser(userPO.getUserId()));
    }

    /**
     * 社区用户统计
     *
     * @param userId
     * @return
     */
    @GetMapping("/community/statistics")
    @AccessControl
    public ApiResult communityStatistics(@CurrentUser UserPO userPO, Long userId) {
        UserPO user = userService.findById(userId);
        long fansCount = 0L;
        if (user != null) {
            fansCount = user.getFansCount();
        }
        boolean followed = false;
        long contentCount = 0L;
        long auditContentCount = 0L;
        if (userPO != null) {
            if (userPO.getId().equals(userId)) {
                contentCount = articleService.countByUser(userPO.getUserId());
                auditContentCount = articleService.countByUserAudit(userPO.getUserId());
            } else {
                followed = followService.isFollowed(userPO.getUserId(), userId);
            }
        }


        Map<String, Object> map = new HashMap<>(6);
        map.put("followCount", userFollowService.followCount(userId));
        map.put("likeCount", articleService.likeCount(userId));
        map.put("fanCount", fansCount);
        map.put("followed", followed);
        map.put("contentCount", contentCount);
        map.put("auditContentCount", auditContentCount);
        return ApiResult.ok(map);
    }


    /**
     * 检查是否拉入黑名单
     *
     * @param type 黑名单类型 0 直播间黑名单 1购买黑名单  其他后续
     * @return
     */
    @ApiOperation("检查是否拉入黑名单")
    @GetMapping("/check/blacklist/{type}")
    @AccessControl
    public ApiResult checkBlacklist(@CurrentUser UserPO user, @PathVariable("type") int type) {

        if (user == null) {
            return ApiResult.ok(true);
        }
        SystemEnums.BlacklistType blacklistType = CodeDescEnumHelper.getEnumTypeByCode(SystemEnums.BlacklistType.class, type);
        if (blacklistType == null) {
            return ApiResult.ok(true);
        }
        return ApiResult.ok(blacklistService.checkByUserId(user.getUserId(), blacklistType));
    }


}
